package rad.framework.mda.jpagen.actions;

import rad.framework.mda.generator.Console;
import rad.framework.mda.util.ModelUtil;

import org.eclipse.emf.common.util.EList;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Enumeration;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Stereotype;

/**
 * @author boudyacho
 * 
 */
public class SwitchIdGeneratorActionExtension extends
		BaseUtiltiyActionExtension {

	protected static final String ID = "javax.persistence.Id";

	protected static final String ENTITY = "javax.persistence.Entity";

	protected static final String GENERATED_VALUE = "javax.persistence.GeneratedValue";

	protected static final String GENERATION_TYPE = "javax.persistence.GenerationType";

	protected static final String SEQUENCE_GENERATOR = "javax.persistence.SequenceGenerator";

	protected static final String GENERIC_GENERATOR = "org.hibernate.annotations.GenericGenerator";

	protected static final String AUTO = "AUTO";

	protected static final String TABLE = "TABLE";

	protected static final String IDENTITY = "IDENTITY";

	protected static final String SEQUENCE = "SEQUENCE";

	protected static final String GENERIC = "GENERIC";

	private String generationType = null;

	public void fillContextMenu(IMenuManager aMenu) {
		getSubMenu(aMenu).add(new SwitchIdGeneratorAction());
	}

	protected void execute(Class clazz) {
		if (ModelUtil.isStereotypeApplied(clazz, ENTITY)) {
			EList<NamedElement> list = clazz.getOwnedMembers();
			for (NamedElement namedElement : list) {
				if (namedElement instanceof Property) {
					try {
						execute((Property) namedElement);
					} catch(Exception e) {
						throw new RuntimeException("Error on: "
								+ namedElement.getQualifiedName(), e);
					}
				}
			}
		}
	}

	protected void execute(Property property) {
		if (ModelUtil.isStereotypeApplied(property, GENERATED_VALUE)) {
			if (generationType.equals(AUTO)) {
				setAuto(property);
			}
			if (generationType.equals(SEQUENCE)) {
				setSequence(property);
			}
			if (generationType.equals(TABLE)) {
				setTable(property);
			}
			if (generationType.equals(IDENTITY)) {
				setIdentity(property);
			}
			if (generationType.equals(GENERIC)) {
				setGeneric(property);
			}
			Console.getStream().println(
					"Set Generation Type for: " + property.getQualifiedName()
							+ " to: " + generationType);
		}
	}

	private void setIdentity(Property property) {
		Console.getStream().println(
				generationType + " generation type not implemented. "
						+ property.getQualifiedName());
	}

	private void setTable(Property property) {
		Console.getStream().println(
				generationType + " generation type not implemented. "
						+ property.getQualifiedName());
	}

	private void setSequence(Property property) {
		if (!ModelUtil.isStereotypeApplied(property, SEQUENCE_GENERATOR)) {
			Stereotype stereotype = (Stereotype) ModelUtil.getProfileElement(
					property, GENERATED_VALUE);
			Element e = ModelUtil.getProfileElement(property, GENERATION_TYPE);
			if (stereotype != null && e != null) {
				if (e instanceof Enumeration) {
					property.setValue(stereotype, "strategy", ((Enumeration) e)
							.getOwnedLiteral(generationType));
					Class clazz = (Class) property.getOwner();
					property.setValue(stereotype, "generator", clazz.getName()
							+ "Seq");
				}
			}

			stereotype = (Stereotype) ModelUtil.getProfileElement(property,
					SEQUENCE_GENERATOR);
			if (stereotype != null) {
				property.applyStereotype(stereotype);
				Class clazz = (Class) property.getOwner();
				property.setValue(stereotype, "name", clazz.getName() + "Seq");
				// TODO Abbreviations
				property.setValue(stereotype, "sequenceName", clazz.getName()
						.toUpperCase()
						+ "_SEQ");
				// TODO profile change
				property.setValue(stereotype, "initialValue", 1);
				property.setValue(stereotype, "allocationSize", 50);
			}
		}
	}

	private void setAuto(Property property) {
		Stereotype stereotype = (Stereotype) ModelUtil.getProfileElement(
				property, GENERATED_VALUE);
		Element e = ModelUtil.getProfileElement(property, GENERATION_TYPE);
		if (stereotype != null && e != null) {
			if (e instanceof Enumeration) {
				property.setValue(stereotype, "strategy", ((Enumeration) e)
						.getOwnedLiteral(generationType));
				property.setValue(stereotype, "generator", "");
			}
		}

		if (ModelUtil.isStereotypeApplied(property, SEQUENCE_GENERATOR)) {
			stereotype = (Stereotype) ModelUtil.getProfileElement(property,
					SEQUENCE_GENERATOR);
			if (stereotype != null) {
				property.unapplyStereotype(stereotype);
			}
		}
	}


	private void setGeneric(Property property) {
		Class clazz = (Class) property.getOwner();
		String generator = clazz.getName() + "IdGenerator";
		String strategy = "rad.framework.hibernate.SequenceAssignedGenerator";
		
		Stereotype stereotype = (Stereotype) ModelUtil.getProfileElement(
				property, GENERATED_VALUE);
		Element e = ModelUtil.getProfileElement(property, GENERATION_TYPE);
		if (stereotype != null && e != null) {
			if (e instanceof Enumeration) {
				if (!isAuto(property, stereotype, e)) {
					strategy = "rad.framework.hibernate.IdentityAssignedGenerator";
					generator = (String) property.getValue(stereotype, "generator");
				} else {
					property.setValue(stereotype, "strategy", null);
					property.setValue(stereotype, "generator", generator);
				}
			}
		}

		stereotype = (Stereotype) ModelUtil.getProfileElement(property,
				GENERIC_GENERATOR);
		if (stereotype != null) {
			property.applyStereotype(stereotype);
			property.setValue(stereotype, "name", generator);
			property.setValue(stereotype, "strategy", strategy);
		}
	}
	
	private boolean isAuto(Property property, Stereotype stereotype, Element e) {
		Object type = ((Enumeration) e).getOwnedLiteral(AUTO);
		Object value = property.getValue(stereotype, "strategy");
		return type.equals(value);
	}
	
	private class SwitchIdGeneratorAction extends BaseUtilityAction {
		private static final String LABEL = "Switch Id Generators";

		public SwitchIdGeneratorAction() {
			super(LABEL);
		}

		public void run() {
			generationType = openInputDialog("Select Generator Type", new String[] { AUTO, SEQUENCE,
					TABLE, IDENTITY, GENERIC });
			if (generationType != null && generationType.length() > 0) {
				super.run();
			}
		}
	}
}
